﻿''' <summary>
''' 后台上传历史数据
''' </summary>
''' <remarks></remarks>
Public Class BackgroundHistorydata

#Region "Single"

    Private Shared _instance As New BackgroundHistorydata

    Public Shared ReadOnly Property Instance() As BackgroundHistorydata
        Get
            Return _instance
        End Get
    End Property

    Sub New()
        If g_test Then
            halfPage1 = 255
            halfPage2 = 255
        End If
        _pi = MainForm.pi
        _bw = New System.ComponentModel.BackgroundWorker()
        _bw.WorkerSupportsCancellation = True
        AddHandler _bw.DoWork, AddressOf DoWork
    End Sub

#End Region

    '历史数据的前半页长度（标志）
    Private halfPage1 As Byte = 1

    '历史数据的后半页长度（标志）
    Private halfPage2 As Byte = 2

    '后台上传的工作线程
    Private WithEvents _bw As System.ComponentModel.BackgroundWorker

    '历史数据上传完成时间
    Public Event HistoryDataUploadFinishedEvent As EventHandler
    '
    Private _pi As ProjectItem

    ''历史数据上传页每页记录条数
    'Const HDUPLOADNUM = 12

    ''历史数据上传页每条记录多少字节
    'Const HDUPLOADBYTE = 42

    ''历史数据半页数量
    'Const HDUPLOADHALFNUM = 6


    '是否取消后台线程
    Private _cancel As Boolean = False

    Private _isStarting As Boolean = False
    ''' <summary>
    ''' 正在准备运行
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property isStarting() As Boolean
        Get
            Return _isStarting
        End Get
        Set(ByVal value As Boolean)
            _isStarting = value
        End Set
    End Property


    ''' <summary>
    ''' 开始执行后台上传
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub Start()

        If _isStarting = True Then  '已经启动线程开始过程
            Exit Sub
        End If

        '_isStarting置为True,表示准备上传
        _isStarting = True

        '等待上次线程的结束(最长等待2分钟)
        For i As Integer = 0 To 1200

            If _bw.IsBusy = False Then
                Exit For
            End If

            System.Threading.Thread.Sleep(100)
            Application.DoEvents()
            If _cancel = True Then
                _isStarting = False
                Exit Sub
            End If
        Next

        '_isStarting置为False,表示准备结束,进入上传状态
        _isStarting = False

        _cancel = False
        _bw.RunWorkerAsync()

    End Sub

    Public Sub StopRead()

        _cancel = True
        If _bw.IsBusy = True Then
            _bw.CancelAsync()
            Application.DoEvents()
        End If

    End Sub


    ''' <summary>
    ''' 后台线程的执行方法
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs)
        Debug.WriteLine("********** 开始历史data后台上传 " & Now.ToLongTimeString())

        '延迟10分钟,然后开始上传
        'System.Threading.Thread.Sleep(10 * 60 * 1000 / g_one1)
        For i As Integer = 0 To 10 * 60 / g_one1
            If _cancel Then
                '取消上传
                Exit Sub
                'Throw New UploadCancelException()
            End If

            System.Threading.Thread.Sleep(1000)
        Next


        '**************************************************************************************
        '2009年06月10日 李吉鹏 修改
        Try
            Select Case MainForm.pi.connectType
                Case 0 '拨号
                    If g_BackgroundUploadHistoryData_Tel Then
                        '上传所有历史数据
#If LSC_DATEUPLOAD_SWICH = "DATE_STARTSTOP_UPLOAD" Then
                        Upload1()
#ElseIf LSC_DATEUPLOAD_SWICH = "DATETIME_UPLOAD" Then
                        Upload()

#End If
                    End If

                Case 1 '直连
                    If g_BackgroundUploadHistoryData_Com Then
                        '上传所有历史数据
#If LSC_DATEUPLOAD_SWICH = "DATE_STARTSTOP_UPLOAD" Then
                        Upload1()
#ElseIf LSC_DATEUPLOAD_SWICH = "DATETIME_UPLOAD" Then
                        Upload()

#End If
                    End If


                Case 2 'TCP
                    If g_BackgroundUploadHistoryData_Tcp Then
                        '上传所有历史数据
#If LSC_DATEUPLOAD_SWICH = "DATE_STARTSTOP_UPLOAD" Then
                        Upload1()
#ElseIf LSC_DATEUPLOAD_SWICH = "DATETIME_UPLOAD" Then
                        Upload()

#End If
                    End If


            End Select


            '***************************************************************************          
        Catch ucex As UploadCancelException
            Debug.WriteLine(ucex.GetType().ToString())
        Catch ex As Exception
            Debug.WriteLine(ex.Message)
        End Try
    End Sub

    ''' <summary>
    ''' 历史数据上传结束 
    ''' </summary>
    ''' <remarks></remarks>
    Protected Sub OnUploadFinished()
        If Not _cancel Then
            RaiseEvent HistoryDataUploadFinishedEvent(Me, New EventArgs())
        End If
    End Sub
    ''' <summary>
    ''' 新上传历史数据
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub Upload1()
        Dim cur_netid As Byte
        Dim cur_Project As String = MainForm.pi.ProjectID
        Dim ssitem As IList(Of HDStartStopItem)
        Dim uppage As List(Of HDStartStopItem)
        Dim upsuc As Boolean = False
        '循环处理所有设备信息
        For Each dti As DevTypeItem In MainForm.pi.DevTypeGroupList

            If dti Is Nothing Then
                Continue For
            End If
            cur_netid = dti.NetId
            HDStartStopClass.ClearBuffer() '清空启停表缓存

            WaitforBusy()

            ssitem = HDStartStopClass.GetAvailItem(cur_Project, cur_netid)  '获取有效启停记录

            If ssitem Is Nothing Then  '记录中没有有效启停记录
                Debug.WriteLine("Availnote = Nothing")
                Continue For
            End If

            WaitFor()

            uppage = HDStartStopClass.GetAvailPage(cur_Project, cur_netid, ssitem)  '获取有效启停记录中未上传页信息

            If uppage Is Nothing Then
                Debug.WriteLine("AvailPage=Nothing")
                Continue For
            End If

            
            For Each item As HDStartStopItem In uppage   '循环上传所有启停记录需要上传页
                WaitFor()
                Dim dt As DateTime = HDStartStopClass.GetNowTimevalue(cur_netid, item.StartUploadPage)
                Dim dt2 As DateTime = HDStartStopClass.GetNowTimevalue(cur_netid, item.EndUploadPage)
                Dim Uploadpagelist As New ArrayList
                Uploadpagelist = HistoryDataClass.GetAvlidRecord(cur_Project, cur_netid, dt, dt2)   '过滤手动上传已经上传的数据页

                For i As Integer = 0 To HIST_ALL_PAGE - 1
                    WaitFor()
                    Dim iPage As Integer

                    iPage = (item.StartUploadPage + i) Mod HIST_ALL_PAGE

                    Try

                        If Uploadpagelist Is Nothing Then    '过滤手动上传已上传页
                        Else
                            If Uploadpagelist.Count > 0 Then
                                If Uploadpagelist.Contains(iPage) Then
                                    If iPage = item.EndUploadPage Then    '上传到该启停记录最后一页，退出循环
                                        Exit For
                                    End If
                                    Continue For
                                End If
                            End If
                        End If

                        Try

                            For k As Integer = 1 To 9  '如果上传失败每页数据循环上传9次
                                upsuc = uploadHour1(cur_Project, cur_netid, iPage, item)
                                If upsuc = True Then
                                    Exit For
                                End If
                            Next
                        Catch ex As Exception

                            Continue For

                        End Try
                       
                        If upsuc = False Then  '如果每页数据上传9次失败退出上传
                            Exit Sub
                        End If

                    Catch ex As Exception
                        'Debug.WriteLine("串口已关闭")
                        Continue For
                    End Try

                    If iPage = item.EndUploadPage Then    '上传到该启停记录最后一页，退出循环
                        Exit For
                    End If
                    System.Threading.Thread.Sleep(5000)



                Next
            Next

        Next

    End Sub
    Private Function uploadHour1(ByVal projectID As String, ByVal netID As Byte, ByVal indexPage As Integer, ByVal HDsspage As HDStartStopItem) As Boolean


        Debug.WriteLine("************ indexPage=" & indexPage & "   " & Now.ToLongTimeString())
        Try

            Dim buf(509) As Byte

            Dim b1(254) As Byte
            Dim devType As Integer


            '历史数据页的前255字节
            b1 = COMHelper.Instance.Send4Byte(netID, FunctionCode.HistoryByteRead, indexPage, halfPage1)
            If b1 Is Nothing Then
                Return False

            End If
            b1.CopyTo(buf, 0)

            System.Threading.Thread.Sleep(1000)

            If _cancel Then
                '取消上传
                Throw New UploadCancelException()
            End If

            '上半页数据长度
            Dim len As Integer = b1.Length

            '历史数据页的后255字节
            b1 = COMHelper.Instance.Send4Byte(netID, FunctionCode.HistoryByteRead, indexPage, halfPage2)
            If b1 Is Nothing Then
                Return False

            End If
            b1.CopyTo(buf, len)

            devType = DevTypeService.GetdevType(projectID, netID)
            Select Case devType
                Case 1
                    '将读取数据存入数据库
                    If HistoryDataClass.DealData1(buf, projectID, netID, indexPage, HDsspage) = False Then
                        Return False
                    End If
                Case 16  '兼容模块数据
                    '将读取数据存入数据库
                    If HistoryDataClass.DealDataEx16(buf, projectID, netID, indexPage, HDsspage) = False Then
                        Return False
                    End If

            End Select

            
            Return True
        Catch ex As Exception

            Throw ex
        End Try



    End Function

    ''' <summary>
    ''' 上传历史数据
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub Upload()

        Dim cur_netid As Byte
        Dim cur_Project As String = MainForm.pi.ProjectID

        For Each dti As DevTypeItem In MainForm.pi.DevTypeGroupList

            cur_netid = dti.NetId

            'If _bw.CancellationPending Then
            '    Debug.WriteLine("################" + _bw.GetHashCode().ToString() + " Exit0")
            '    Exit For
            'End If

            PowerTimeClass.ClearBuffer()

            WaitforBusy()  '未读取报警索引文件前可进行busy等待,而不需要退出

            '读取掉电现场数据的每个区域保存时间(年,月,日)
            Dim dic As IDictionary(Of Integer, DateTime)
            dic = PowerTimeClass.GetHistoryDataYearMonth(cur_netid)

            If dic Is Nothing Then
                Debug.WriteLine("dic = Nothing")
                'Throw New Exception(" 读取掉电现场数据失败")
                'Exit Sub
                Continue For
            End If

            WaitFor()

            Dim dt As DateTime

            Dim dtCurrent As DateTime
            dtCurrent = COMHelper.Instance.getCurrentTime(cur_netid)

            If dtCurrent = DateTime.MinValue Then
                '读取控制器时间失败
                dtCurrent = COMHelper.Instance.getCurrentTime(cur_netid)

                If dtCurrent = DateTime.MinValue Then
                    Continue For
                End If

            End If

            WaitFor()

            dtCurrent = dtCurrent.AddSeconds(-1 * HIST_SAVE_INTERVAL_TIME * HIST_COUNT_EACH_PAGE - 20)

            Dim pageIndex As Integer = 0

            '循环处理所有历史日期的数据

            For Each kv As KeyValuePair(Of Integer, DateTime) In dic
                pageIndex = kv.Key * HIST_PLANPAGECOUNT_EACHAREA  '区地址

                dt = kv.Value

                Dim dtUpdatedDate As DataTable

                '获取该天所有已经上传的历史数据的索引记录
                dtUpdatedDate = GetHistory(cur_Project, cur_netid, dt)


                '循环上传某天的所有历史数据
                For i As Integer = 0 To HIST_USEDPAGECOUNT_EACHAREA - 1

                    WaitFor()

                    dt = kv.Value.AddSeconds(i * HIST_SAVE_INTERVAL_TIME * HIST_COUNT_EACH_PAGE)

                    If dt > dtCurrent Then
                        '历史数据的时间不能超过子控的当前时间
                        Debug.WriteLine("dt > dtCurrent  (exit for)")
                        Exit For
                    End If

                    '是否在掉电期间
                    If PowerTimeClass.HistoryDataValidate(cur_netid, dt) = False Then
                        '掉电期间的无效数据，不上传
                        Continue For
                    End If

                    '是否已经上传
                    Dim filter As String
                    filter = String.Format("iHour={0} and iMinute={1} and iSecond={2}", dt.Hour, dt.Minute, dt.Second)
                    If dtUpdatedDate.Select(filter).Length = 0 Then       '历史数据未上传
                        '上传历史数据
                        'uploadHour(cur_Project, cur_netid, pageIndex + i, dt)
                        For k As Integer = 1 To 3
                            If uploadHour(cur_Project, cur_netid, pageIndex + i, dt) = True Then
                                Exit For
                            End If
                        Next
                        System.Threading.Thread.Sleep(5000)
                    End If
                Next
            Next
        Next
    End Sub


    ''' <summary>
    ''' 上传指定设备、指定时间（年月日小时）的历史数据
    ''' </summary>
    ''' <param name="netID"></param>
    ''' <param name="indexPage"></param>
    ''' <param name="dt"></param>
    ''' <remarks></remarks>
    Private Function uploadHour(ByVal projectID As String, ByVal netID As Byte, ByVal indexPage As Integer, ByVal dt As DateTime) As Boolean
        Debug.WriteLine("************ indexPage=" & indexPage & "   " & Now.ToLongTimeString())

        Dim buf(34 * 15 - 1) As Byte

        Dim b1(17 * 15 - 1) As Byte

        '历史数据页的前255字节
        b1 = COMHelper.Instance.Send4Byte(netID, FunctionCode.HistoryByteRead, indexPage, halfPage1)
        If b1 Is Nothing Then
            Return False
            Exit Function
        End If
        b1.CopyTo(buf, 0)

        System.Threading.Thread.Sleep(100)

        If _cancel Then
            '取消上传
            Throw New UploadCancelException()
        End If

        '上半页数据长度
        Dim len As Integer = b1.Length

        '历史数据页的后255字节
        b1 = COMHelper.Instance.Send4Byte(netID, FunctionCode.HistoryByteRead, indexPage, halfPage2)
        If b1 Is Nothing Then
            Return False
            Exit Function
        End If
        b1.CopyTo(buf, len)

        HistoryDataClass.DealData(dt, buf, projectID, netID)
        'HistoryDataClass.DealFinish(projectID, dt, netID)
        Return True

    End Function

    ''' <summary>
    ''' 获取指定年月已经上传的历史数据的记录
    ''' </summary>
    ''' <param name="netID"></param>
    ''' <param name="dt"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function GetHistory(ByVal pid As String, ByVal netID As Integer, ByVal dt As DateTime) As DataTable
        Dim strSql As String
        strSql = String.Format("Select * From tbccHistorydata_{0} where netID=?p0 and iYear=?p1 and iMonth=?p2 and iDay=?p3", Trim(pid).Replace("-", "_"))
        Dim p(3) As MySql.Data.MySqlClient.MySqlParameter
        For i As Integer = 0 To p.Length - 1
            p(i) = New MySql.Data.MySqlClient.MySqlParameter()
        Next
        p(0).ParameterName = "p0" : p(0).Value = netID
        p(1).ParameterName = "p1" : p(1).Value = dt.Year
        p(2).ParameterName = "p2" : p(2).Value = dt.Month
        p(3).ParameterName = "p3" : p(3).Value = dt.Day

        Dim ds As DataSet
        ds = SqlHelper.ExecuteDataset(strSql, p)

        Return ds.Tables(0)
    End Function

    ''' <summary>
    ''' 读取指定设备的当前历史数据的年月列表
    ''' </summary>
    ''' <param name="netID"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Shared Function GetYearMonths(ByVal netID As Byte) As Dictionary(Of Integer, Integer)
        Dim ymList As Dictionary(Of Integer, Integer)

        ymList = PowerTimeClass.GetHistoryDataYearMonth(netID)

        If ymList Is Nothing Then
            ymList = New Dictionary(Of Integer, Integer)
        End If

        Return ymList
    End Function

    ''' <summary>
    ''' 判断是否其它地方正在读取数据
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub WaitFor()

        '其它地方正在修改参数或者前台上传时取消后台上传
        If g_busy OrElse g_dbbackup Then
            '取消上传
            Throw New UploadCancelException()
        End If

        If _cancel Then
            '取消上传
            Throw New UploadCancelException()
        End If

    End Sub


    ''' <summary>
    ''' 暂停等待busy一段时间
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub WaitforBusy()

        If _cancel Then
            '取消上传
            Throw New UploadCancelException()
        End If

        '其它地方正在修改参数或者前台上传时暂停后台上传
        While (g_busy OrElse g_dbbackup)
            System.Threading.Thread.Sleep(100)

            If _cancel Then
                '取消上传
                Throw New UploadCancelException()
            End If

        End While

    End Sub



    ''' <summary>
    ''' 后台线程运行结束
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub _bw_RunWorkerCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles _bw.RunWorkerCompleted
        OnUploadFinished()
    End Sub
End Class
